
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#include "ulog/ulog.h"
#include "user_task.h"
#include "gpio/gpio.h"
#include "stdio.h"
#include "drv_spiflash.h"
#include <drv_mailbox.h>
#include "ipcm.h"
#include "app_init.h"
#include "data_move.h"
#include "debug_time.h"
#include "flash_indirect_opt.h"
//#include "lvgl.h"
//#include "demo_ui.h"
#include "pic_crop.h"
#include "eeprom_read_data.h"
#include "if_v.h"
#include "faceproc.h"
#include "limoi-videoiva11-jpeg-decoder.h"
// #include "A_base_720x1280.h"
#include "vfs.h"
#include <aos/hal/flash.h>

#include "board.h"
#include "flash_partitions.h"
#include "drv_delay.h"

#define WEIGHT_FILE_IMAGE_NAME "WeightFile_IMAGE.bin"

#if defined(WEIGHT_MEMORY_ADDR)

//#define WEIGHT_MEMORY_ADDR   0x3600000
#define WEIGHT_FLASH_ADDR  (0xc035A000+0x10)       //0x10 is magic number offset
#if defined(AOS_BOARD_TX5103C_LOCK_HC)
#define WEIGHT_LENGTH       (10 * 1024 * 1024 - 512 * 6 * 4)
#else
#define WEIGHT_LENGTH       (10 * 1024 * 1024)
#endif

#elif defined (AOS_BOARD_TX510_TOF)

#define WEIGHT_MEMORY_ADDR   0x3600000
#define WEIGHT_FLASH_ADDR   (0xc0392000+0x10)       		   //0x10 is magic number offset
#define WEIGHT_LENGTH       (10 * 1024 * 1024)

#else 

#define WEIGHT_MEMORY_ADDR   0x01c00000
#define WEIGHT_FLASH_ADDR    0xC0744000     		   //0x10 is magic number offset
#if defined(AOS_BOARD_TX5103C_LOCK_HC)
#define WEIGHT_LENGTH       (10 * 1024 * 1024 - 512 * 6 * 4)
#else
#define WEIGHT_LENGTH       (9150464)
#endif

#endif 

extern int32_t hal_qflash_adapt_mutex_lock();
extern int32_t hal_qflash_adapt_mutex_unlock();


static const char *TAG = "USER-TASK: ";

#define COLOR_TO_MTK_COLOR_SIMUL(color) ((((color) >> 19) & 0x1f) << 11) |((((color) >> 10) & 0x3f) << 5) |(((color) >> 3) & 0x1f)

aos_sem_t 	sem_data_move_over;
aos_mutex_t mutex_flash_rw;
aos_sem_t   sem_openlock;
aos_sem_t   sem_powerdown; 
aos_timer_t timer_gui_label;

#define SPEAKER_DELAY_NUM   405   //100us
extern spiflash_handle_t spiFlashHandle;
enum SHOW_MODE show_mode;

int QSPI_flash_face_features_save()
{	
	for(int i=0;i<24;i+=4){
		csi_spiflash_erase_sector(spiFlashHandle, QSPI_AIEINIT_DATA_BASEADDR + i*1024);    //erase	4k  erase all 24k
	}
	int ret = csi_spiflash_program(spiFlashHandle, QSPI_AIEINIT_DATA_BASEADDR, (char *)0x7e00000, ONE_FACE_FEATURE_SIZE*2*30);
    return ret;
}

void QSPI_flash_face_features_read()
{
    memcpy((char *)0x7e00000,(char *)QSPI_AIEINIT_DATA_BASEADDR,ONE_FACE_FEATURE_SIZE*2*30);
}

void user_task(void *arg)
{
    LOGI(TAG,"user_task start\n");

	aos_sem_new(&sem_openlock, 0);
	csi_gpio_pin_write(pin_mipi_pwr, 1);
    while(1)
    {
		aos_sem_wait(&sem_openlock, AOS_WAIT_FOREVER);	
		printf("open lock\n");
		csi_gpio_pin_write(pin_lock,1);
		aos_msleep(500);
		csi_gpio_pin_write(pin_lock,0);
	}
}

void check_memory(const uint8_t* des_data,const uint8_t* right_data,uint32_t len,const char *str)
{
	if (0 != memcmp(des_data, right_data, len))
	{
		printf("%s error\n",str);

		for (uint32_t i = 0; i < len; i++) {
			if (des_data[i] != right_data[i]) {
				printf("pos=%d\tflash_addr=%p mem_addr=%p flash_val=%d mem_val=%d\n", i, &des_data[i], &right_data[i], des_data[i], right_data[i]);
			}
		}
		printf("finish second check\n");

		while (1)
			;
	}
	else
	{
		printf("%s  ok\n",str);
	}
}

void flash_data_move_func(uint8_t* dst, uint8_t* src, uint32_t size)
{
#ifdef KV_DDR_MIRROR_ENABLE
    aos_mutex_lock(&mutex_flash_rw, AOS_WAIT_FOREVER);
    memcpy_with_sleep(dst, src, size);
    aos_mutex_unlock(&mutex_flash_rw);
#endif
}

void flash_data_move_task( void *arg)
{
	int 				 ret = 0;
	// int 				fd   = -1;
	// struct aos_stat file_st  = {0};
	// char			file_name[128] = {0};
	/*Copy weigh file data */  
	LOGD(TAG, "weight move from flash start");
#if defined(AOS_COMP_FLASH)
	ret = indirect_memcpy_dma_linked((uint8_t *)WEIGHT_MEMORY_ADDR, (uint8_t *)WEIGHT_FLASH_ADDR, WEIGHT_LENGTH);
#else
	unsigned int		 offset = 0;
	//0x10 is magic number offset 
	#if 1
	offset = 0x10;
	ret = hal_flash_read(HAL_PARTITION_WEIGHT,&offset,(uint8_t *)WEIGHT_MEMORY_ADDR,WEIGHT_PARTITION_SIZE);
	#else
	snprintf(file_name,sizeof(file_name)-1,"%s/%s",FS_ROOT_PATH,WEIGHT_FILE_IMAGE_NAME);
	printf("%s:%d enter aos_open file_name:%s.\n",__FUNCTION__,__LINE__,file_name);
	fd = aos_open(file_name, O_RDONLY);	
	if (fd < 0) 
	{
		printf("%s:%d enter aos_open file_name:%s fd:%d err.\n",__FUNCTION__,__LINE__,file_name,fd);
		return;
	}
	ret = aos_stat(file_name,&file_st);	
	printf("%s:%d enter aos_open file_name:%s size:%d.\n",__FUNCTION__,__LINE__,file_name,file_st.st_size);
	if(!ret && (file_st.st_size > 0))
	{
		ret = aos_read(fd, (uint8_t *)WEIGHT_MEMORY_ADDR, file_st.st_size);	
	}
	aos_close(fd);	
	#endif
#endif
}
#define WEIGHT_PATH "/sdcard/weight/weight"
void weight_data_move_from_sdcard( void *arg)
{
	long long time_enter, time_exit;
	int move_offset = 0;
	int move_step = 1024;
	int move_block = 1;
	uint64_t read_bit;
	int file_size;
	LOGD(TAG, "weight move start");
    FILE *fp = fopen(WEIGHT_PATH, "r");
	if (!fp) {
        printf("Open file failed: %s\n", WEIGHT_PATH);
        return;
    }
	fseek(fp,0,SEEK_END);
	file_size = ftell(fp);
	fseek(fp,0,SEEK_SET);

	time_enter = aos_now_ms();
	while (!feof(fp)) {
		read_bit = fread((void *)(WEIGHT_MEMORY_ADDR + move_offset), move_block, move_step, fp);
		move_offset+=read_bit*move_block;
	}
	fclose(fp);
	time_exit = aos_now_ms();

	LOGD(TAG, "weight move done, size = %d time:%lld", move_offset, (time_exit - time_enter));
}

int check_flash_data_move_done()
{
#if defined(AOS_COMP_FLASH)
	printf("wait dma\n");
	while (!dma_cb_flag){
		aos_msleep(1);
	}
	LOGD(TAG, "%s:%d enter,copy weight,dma_cb_flag:0x%x\n",__FUNCTION__,__LINE__,dma_cb_flag);
	hal_qflash_adapt_mutex_unlock();
#endif
	return 0;
}

void check_memory_data_consistency()
{
#if defined(AOS_COMP_FLASH)
    check_memory((uint8_t *)WEIGHT_FLASH_ADDR,(uint8_t *)WEIGHT_MEMORY_ADDR, WEIGHT_LENGTH,"weight check");
#endif
}

#if 0
void timer_gui_label_cb(void *arg,void *arg2)
{
   //printf("Clear recognition\n");
   ui_recognition_clear();
}

void timer_gui_lable_reset(void)
{
    aos_timer_stop(&timer_gui_label);
    aos_timer_start(&timer_gui_label);	
}

void gui_lvgl_task(void *arg)
{
    aos_timer_new(&timer_gui_label, timer_gui_label_cb, NULL, 500, 0);
    lv_port_disp_init();
	demo_ui_init(); 	 /* ui initialization */
	ui_show_test("tsingmicro");
    while(1) 
	{
		lv_task_handler();
        aos_msleep(5);
    }
}
#endif

void power_down_task(void *arg)
{
    int power_down_mark = 0;
	aos_sem_new(&sem_powerdown, 0);
	aos_sem_wait(&sem_powerdown, -1);
	printf("Power down system! \n");
	while(1)	 
	{
	    csi_gpio_pin_write(pin_power_down, 0);
		udelay(500);  //0.5ms
	    csi_gpio_pin_write(pin_power_down, 1);  
		udelay(500);  //1ms
		printf("power_down_mark = %d\n", power_down_mark++);
	}
}
int  get_match_pool_num()
{
	if(*(int *)REFACE_NUM_ADR < 0) *(int *)REFACE_NUM_ADR =0;
	return *(int *)REFACE_NUM_ADR;
}

void set_match_pool_num(int x)
{
	*(int *)REFACE_NUM_ADR = x;
}

//缩放截图
void imageShots(uint32_t *pSrc, uint32_t srcWidth, uint32_t srcHeight, char *pDst,uint32_t dstWidth, uint32_t dstHeight)
{
	if((NULL == pSrc) || (NULL == pDst))
	{
		return;
	}
	uint32_t i,j = 0;
	uint32_t widthOffset,heightOffset = 0;
	uint32_t *pStartAdr = NULL;
	
	int station=0;
	int picture_data;
	unsigned char input[4];
	int rgb565=0;
	int isrcWidth =0;
	widthOffset = (srcWidth - dstWidth) / 2 ;
	heightOffset = (srcHeight - dstHeight) / 2 ;

	pStartAdr = pSrc + srcWidth*heightOffset + widthOffset;
	for(i=0;i<dstHeight;i++) //320 row
	{
	    station = 480*(i+1);
		isrcWidth = i*srcWidth;
		for(j=0;j<dstWidth;j++) //240 column
		{
			picture_data = *(pStartAdr + isrcWidth + j);
            input[0] = (unsigned char)(picture_data>>16);
			input[1] = (unsigned char)(picture_data>>8);
			input[2] = (unsigned char)picture_data; 
			rgb565 = COLOR_TO_MTK_COLOR_SIMUL((input[0]<<16) | (input[1]<<8) | input[2]);
				
			*(short int*)(pDst + station -2*(j+1)) = (unsigned char)(rgb565) |((unsigned char)(rgb565>>8)<<8);
	        //*(short int*)(pDst + station -2*(j+1)) =0xff;
		}
	}
}

void IrToRGB565(char *p_src, uint32_t src_width, uint32_t src_height, char *p_dst, uint32_t dst_width, uint32_t dst_height)
{
	if((NULL == p_src) || (NULL == p_dst))
	{
		return;
	}
	
	uint32_t i = 0, j = 0;
	char ir_image_data;
	int rgb565 = 0;
	int station = 0;
	int isrc_width = 0;
	uint32_t width_offset, height_offset = 0;
	char *p_start_adr = NULL;
	width_offset = (src_width -dst_width) / 2 ;
	height_offset = (src_height -dst_height) / 2 ;

	p_start_adr = p_src +src_width *height_offset +width_offset;  //
	for (i = 0; i < dst_height; i++) //320 row
	{
		station = 480 * (i +1);
		isrc_width = i *src_width;
		for(j = 0; j < dst_width; j++) //240 column
		{
			ir_image_data = *(p_start_adr + isrc_width + j);
			rgb565 = COLOR_TO_MTK_COLOR_SIMUL((ir_image_data <<16) | (ir_image_data <<8) | ir_image_data);
			*(short int*)(p_dst +station -2 *(j +1)) = (unsigned char)(rgb565) | ((unsigned char)(rgb565 >>8) <<8); 			
		}
	}
}

int light_intensity(uint32_t *p_src, uint32_t src_width, uint32_t src_height)
{
	uint32_t width_offset, height_offset = 0;
	uint32_t i = 0;
	int brightness_add_x =0 ,brightness_add_y =0;
	int abgr =0;
	int start_adr =0;
	width_offset  = src_width / 2;
	height_offset = src_height / 2;
	start_adr = src_width *height_offset;
  	for(i =0; i <src_height; i++)  	//Vertical row
  	{
  			abgr = *(p_src + width_offset + i *src_width);
			brightness_add_y += (unsigned char)abgr;
			brightness_add_y += (unsigned char)(abgr >>8);
			brightness_add_y += (unsigned char)(abgr >>16);
  	}
  	
 	for(i =start_adr; i <(start_adr +src_width); i++)
 	{
  			abgr = *(p_src +i);
			brightness_add_x += (unsigned char)abgr;
			brightness_add_x += (unsigned char)(abgr >>8);
			brightness_add_x += (unsigned char)(abgr >>16);
 	}
	return brightness_add_x +brightness_add_y;
 }

void light_intensity_get(void *arg)
{
	show_mode = ABGR;
	while(1)
	{
		if(light_intensity((uint32_t*)ABGR_BUF_ADR,SRC_WIDTH,SRC_HEIGHT) > LIG_INT_NUM_TEST){
		   show_mode = ABGR;
		}
		else{
		   show_mode = IR;
		}
		aos_msleep(500);	
	}
}

void picture_conversion_task(void *arg)
{
	//aos_task_new("light_intensity_handle", light_intensity_get, NULL, 1024);
	//show_mode = IR;
	//printf("show_mode = IR;\n");
	while(1)
	{
		if(show_mode == IR){
		   IrToRGB565((char *)IR_BUF_ADR,SRC_WIDTH,SRC_HEIGHT, (char *)DST_ADR,DST_WIDTH,DST_HEIGHT);
		}
		else {  //ABGR
		   imageShots((uint32_t *)ABGR_BUF_ADR,SRC_WIDTH,SRC_HEIGHT, (char *)DST_ADR,DST_WIDTH,DST_HEIGHT);	   
		}	
		
		aos_msleep(10);
	}  
}

int getFlashSpkBaseFlag(void)
{
	int ret = 0;
	volatile uint32_t *base;
	// SN_inf_t SN_data;
	// char sensor_type_name[3][8] = {"SL","Tof","Stereo"};
	hal_qflash_adapt_mutex_lock();	
	base = (uint32_t *)QSPI_SENSOR_PARAM_BASEADDR; 
	printf("flag %d \n", *base);
	hal_qflash_adapt_mutex_unlock();
	if(1 == *base){
		ret = 0;
	}
	else{
		ret = -1;
	}
	
	// SN_data = eeprom_read_SN_data();
	// printf("SN_data s-num: %s%02d-%d%d-%d \n",sensor_type_name[SN_data.name_type-1],SN_data.part_number,
	// 						SN_data.year_number,SN_data.week_number,SN_data.product_ID);

	return ret;
}

int readFlashSensorPara(sensor_para_t *pSensorPara)
{
	// volatile uint32_t *base;

	if(NULL == pSensorPara)
		return -1;
	hal_qflash_adapt_mutex_lock();
	//indirect_memcpy_dma_linked((uint8_t *)pSensorPara, (uint8_t *)QSPI_SENSOR_PARAM_BASEADDR, sizeof(sensor_para_t));
	//memcpy_with_sleep((uint8_t *)pSensorPara, (uint8_t *)QSPI_SENSOR_PARAM_BASEADDR, sizeof(sensor_para_t));
	memcpy((uint8_t *)pSensorPara, (uint8_t *)QSPI_SENSOR_PARAM_BASEADDR, sizeof(sensor_para_t));
	hal_qflash_adapt_mutex_unlock();
	return 0;
}

int writeFlashSensorPara(sensor_para_t *pSensorPara)
{
	int ret = 0;
	// volatile uint32_t *base;

	if(NULL == pSensorPara)
		return -1;
	qspi_flash_write(QSPI_SENSOR_PARAM_BASEADDR, (uint8_t *)pSensorPara, sizeof(sensor_para_t));
	return ret;
}

#if 1

double calibPara[14] = {0.0};
sensor_para_t *sensor_para = NULL;

// int readBasePic(void)
// {
// 	int ret = 0;
// 	uint8_t snUpdateFlag = 0;
// 	uint32_t picSize = 0;
// 	uint32_t curSN = 0;

// 	sensor_para = (sensor_para_t *)aos_malloc(sizeof(sensor_para_t));
// 	if(NULL == sensor_para)
// 	{
// 		printf("mem malloc failed\n");
// 		return -1;
// 	}

// 	memset(sensor_para, 0, sizeof(sensor_para_t));
	
// 	curSN = eeprom_read_SN_data();
// 	if(curSN)
// 	{
// 		ret = getFlashSpkBaseFlag();
// 		if(0 == ret)
// 		{
// 			printf("read base\n");
// 			readFlashSensorPara(sensor_para);
// 			printf("read sn : %08x \n", sensor_para->SN);
// 			if(curSN == sensor_para->SN)
// 			{
// 				printf("calib:%.5f \n", sensor_para->calibPara);
// 			}
// 			else
// 			{
// 				snUpdateFlag = 1;
// 			}
// 		}
		
// 		if((ret < 0) || (snUpdateFlag == 1)) 
// 		{
// 			uint8_t *spkData = (uint8_t *)aos_malloc(128*1024);
// 			if(NULL == spkData)
// 			{
// 				printf("mem malloc failed\n");
// 				return -1;
// 			}
// 		#if defined (MINI_STRUCTURE_LIGHT_MODULE)
// 			uint8_t *spkDataTemp = (uint8_t *)aos_malloc(900*1024);
// 		#else
// 			uint8_t *spkDataTemp = (uint8_t *)aos_malloc(225*1024);
// 		#endif
// 			if(NULL == spkDataTemp)
// 			{
// 				printf("mem malloc failed\n");
// 				return -1;
// 			}
			
// 			sensor_para->SN = curSN;
// 			eeprom_read_intri_param(calibPara);
// 			printf("calib data fx : %.15f \n" ,calibPara[0]);
// 			printf("calib data fy : %.15f \n" ,calibPara[4]);

// 			if(0 == calibPara[0]){
// 				printf("**************** the module no calibration ********************** \n");
// 				return -1;
// 			}
			   
// 			picSize = eeprom_read_image_data(spkData);
// 			printf("picSize %d \n" ,picSize);

// 			sensor_para->calibPara = calibPara[0];
// 		#if defined (MINI_STRUCTURE_LIGHT_MODULE)
// 			uint8_t *image_data = (uint8_t *)aos_malloc(900*1024);
// 		#else
// 			uint8_t *image_data = (uint8_t *)aos_malloc(225*1024);
// 		#endif
// 			if(NULL == image_data)
// 			{
// 				printf("mem malloc failed\n");
// 				return -1;
// 			}

// 			jpeg_to_raw((char *)spkData,picSize,(char *)spkDataTemp,NULL,NULL,EXT_RAW);
// 			printf("convert done \n");
// 			//image_8bits_rotate_right_90(spkDataTemp, sensor_para->basePic,640,360);
// 		#if defined (MINI_STRUCTURE_LIGHT_MODULE)
// 			image_8bits_rotate_right_90(spkDataTemp, image_data,1280,720);
// 		#else
// 			image_8bits_rotate_right_90((char *)spkDataTemp, (char *)image_data,640,360);
// 		#endif
// 			printf("rotate done \n");

// #if 1	
// 			grey_img_t in, out;
// #if defined (MINI_STRUCTURE_LIGHT_MODULE)
// 			in.img = image_data;
// 			in.h   = 1280;
// 			in.w   = 720;
// 			out.h  = 640;
// 			out.w  = 720;
// #else
// 			in.img = image_data;
// 			in.h   = 640;
// 			in.w   = 360;
// 			out.h  = 640;
// 			out.w  = 360;
// #endif
// 			omx_algo_image_bina(&in, &out);
// 			memcpy(sensor_para->basePic, out.img, out.h*out.w);
// #endif
// 			sensor_para->flag = 1;

// 			writeFlashSensorPara(sensor_para);

// 			if(spkData)A_base_720x1280.h
// 				aos_free(spkData);
// 			if(spkDataTemp)
// 				aos_free(spkDataTemp);
// 			if(image_data)
// 				aos_free(image_data);
// 		}
// 	}

// 	return 0;
// }

int writeFlashRegisterType(uint8_t *register_type)
{
	int ret = 0;

	ret = qspi_flash_write(QSPI_REGISTER_TYPE, (uint8_t *)register_type, sizeof(uint8_t));
	
	return ret;
}

int readFlashRegisterType(uint8_t * type_value)
{

	//indirect_memcpy_dma_linked((uint8_t *)pSensorPara, (uint8_t *)QSPI_SENSOR_PARAM_BASEADDR, sizeof(sensor_para_t));
	memcpy_with_sleep((uint8_t *)type_value, (uint8_t *)QSPI_REGISTER_TYPE, sizeof(int));

	return 0;
}
#endif
